/**
 * @class   wosh::SystemProfiler
 * @brief   Singleton component which stores profiling data and deprecated-call list.
 *          Component may be disabled (by configuration), eventually it is owned by
 *          wosh::SystemMonitor core-module.
 * @warning Component and its architecture is still experimental.
 * @see     \ref page_debug_profiling
 * @see     \ref page_debug_deprecated
 * @see     wosh::SystemMonitor
 ****************************************************************************
 * @version 0.8.378 $Id: SystemProfiler.h 2863 2010-08-07 04:28:58Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/*! \page page_debug Debugging
 * \htmlonly <hr/> \endhtmlonly
 * \section page_debug_profiling WOSH Profiling
 *
 * \note Profiling has been officially introduced since WOSH 0.8.151 [icarus]
 * \warning Profiling architecture is still experimental.
 *
 * Profiling allows you to learn where a program spent its time and which
 * functions called which other functions while it was executing.
 *
 * @todo [..]
 *
 * \verbatim
root@wosh28:Monitor# profiles connectors
  BusConnector Profiling data [AC>0]:
  Address           BusName      ParentName        ParentClass #Incoming #Outgoing
----------------------------------------------------------------------------------
 0012FE4C     wosh.Bus.Core          wosh28            UNKNOWN        42         4
 012E0D70     wosh.Bus.Core    SystemLogger            UNKNOWN        42         0
 0130C0B8 wosh.Bus.Security SecurityManager            UNKNOWN        13         0
 013119C8     wosh.Bus.Core   BundleManager            UNKNOWN        41         0
 0131AD28     wosh.Bus.Core   DeviceManager            UNKNOWN        41         1
 0131B0A8  wosh.Bus.Devices   DeviceManager            UNKNOWN         1         0
[..]
\endverbatim
 *
 * \verbatim
root@wosh28:Monitor# profiles methods
  Methods Profiling data [AC>0]:
  Address                Name                       ClassLFLP                  ParentName           ParentClass Calls C-Calls
-----------------------------------------------------------------------------------------------------------------------------
 012E2B28         method_list wosh::MethodMessageResponse 1 1             wosh.WoshModule      wosh::WoshModule     0       0
 012E3230            prop_get wosh::MethodMessageResponse 1 1             wosh.WoshModule      wosh::WoshModule     0       0
 012E3938            prop_set wosh::MethodMessageResponse 1 1             wosh.WoshModule      wosh::WoshModule     0       0
 012E4040           prop_list wosh::MethodMessageResponse 1 1             wosh.WoshModule      wosh::WoshModule     0       0
 012E4748           props_get wosh::MethodMessageResponse 1 1             wosh.WoshModule      wosh::WoshModule     0       0
 012E5288                list         wosh::MethodRequest 1 1                SystemLogger    wosh::SystemLogger     0       0
 012E5990       list_handlers         wosh::MethodRequest 1 1                SystemLogger    wosh::SystemLogger     0       0
[..]
\endverbatim
 *



 * \warning Profiling data is *very* huge (hundreds of Kb) and it's generally too big for current TCP buffers (transport architecture).
 *          In other words, such listing (table) often can't be transmitted to the WOSH network.
 *          The I/O within an host (working on local-host) obviously works fine.
 *
 * \par Linux, GCC:
 *  
 * \see http://www.cs.utah.edu/dept/old/texinfo/as/gprof.html
 *
 *
 * \htmlonly <hr/> \endhtmlonly
 ****************************************************************************
 * \section page_debug_deprecated Deprecated functionalities
 *
 * \note Deprecated-List has been officially introduced in WOSH 0.8.151 [icarus]
 * \warning Deprecated-List is still experimental.
 *
 * Since WOSH is still in development stage, there may be some old (deprecated) functionalities
 * (methods) which are still available, but are discouraged/replaced and will be removed.
 *
 * This information is defined within code (by developer) through a simple macro:
 * \code
void myClass::myDeprecatedMethod( int arg1 ) {
	WOSH_DEPRECATE( "myClass::myDeprecatedMethod", "myClass::newOptimizedMethod" )
 }
 * \endcode
 * The \c macro (code) is evaluated at run-time and will log the call (entry) into wosh::SystemProfiler.
 * Since SystemProfiler is a meyer singleton, developer may insert the macro anywhere at any initialization
 * level (time).
 *
 * \note Deprecated-list is stored in wosh::SystemProfiler, when Profiling is disabled, the \c macro does nothing.
 *
 *
 * You may easily view the list of deprecated calls executing in a shell:
 * \verbatim
root@wosh28:Monitor# deprecated
  Deprecated List:
                (Old) FunctionName New FunctionName Called From                 FileName FileLine
-------------------------------------------------------------------------------------------------
 SystemMonitor::mmDoListDeprecated           SAMPLE    01B6FD74 .\core\SystemMonitor.cpp      399
\endverbatim
 *
 * FileName and FileLine are automatically filled by the MACRO.
 *
 * The \c "Called From" field is not available on all platform yet, it represent the address of the
 * caller method.
 *
 * Deprecated-list is not evaluated by diagnostic system neither monitoring/security systems,
 * it is provided for debugging purposes and human interaction.
 *
 *
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR MutexS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 // IDEA:  specialization for { Property, Method, BusConnector }
 // more specific profiling should be done with standard/specific c++ tools


#ifndef __WOSH_Core_SystemProfiler_H__
 #define __WOSH_Core_SystemProfiler_H__

 #include <woshDefs.h>
 #include <core/Containers.h>
 #include <core/Serialization.h>


namespace wosh {

 // profiling classes:
 class Method;
 class MethodRunner;
 class Property;
 class IPropertiesProviderListener;
 class BusConnector;
 class IBusListener;

 // outputs:
 class List;
 class Table;
 template <class T> class DataFieldCollector;


class DeprecatedFunctionInfo : public ISerializable
 {
	WOSH_SERIALIZABLE(wosh::DeprecatedFunctionInfo)
	WOSH_COMPARE_RTTI(wosh::DeprecatedFunctionInfo)

	public:
		DeprecatedFunctionInfo()
			: CalledFrom(NULL), FileLine(-1) { }
		DeprecatedFunctionInfo( const char * oldFunctionName, const char * newFunctionName,
								void* calledFrom, const char * filename, unsigned int file_line );
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		DeprecatedFunctionInfo( const DeprecatedFunctionInfo& m ) {
			*this = m;
		 }
		/**
		 * @brief  Empty destructor.
		 */
		~DeprecatedFunctionInfo() { }

/** @name Getters
 * @{
 ******************************************************************************/
	public:
		inline const std::string& getOldFunctionName() const	{ return this->OldFunctionName; }
		inline const std::string& getNewFunctionName() const	{ return this->NewFunctionName; }
		inline const std::string& getFileName() const			{ return this->FileName; }
		inline int getFileLine() const							{ return this->FileLine; }

		static DataFieldCollector<DeprecatedFunctionInfo>* getDataFields();
//@}
/** @name Operators Overloading
 * @{
 ******************************************************************************/
	public:
		virtual DeprecatedFunctionInfo& operator=(const DeprecatedFunctionInfo& m);
		virtual bool operator==(const DeprecatedFunctionInfo &other) const;
		virtual bool operator!=(const DeprecatedFunctionInfo &other) const { return !(*this == other); }
//@}
/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const;
		virtual bool updateHash( DataHashContext* hash_context ) const;
//@}
	public:
		std::string OldFunctionName;	///< deprecated method name
		std::string NewFunctionName;	///< new method name/additional info
		void* CalledFrom;				///< caller's address (on x86 architecture only)
		std::string FileName;			///< source code filename (using __FILENAME__)
		unsigned int FileLine;			///< source code file-line (using __FILELINE__)

}; // class def


class ProfileInfo : public ISerializable
 {
	WOSH_SERIALIZABLE_ABSTRACT(wosh::ProfileInfo)
	WOSH_COMPARE_RTTI(wosh::ProfileInfo)

	public:
		/**
		 * @brief  Empty constructor.
		 */
		ProfileInfo()
			: ptr(NULL), accessCount(0), concurrentCount(0), parentPtr(NULL), parentClass("VOID") { }
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		ProfileInfo( const ProfileInfo& m ) {
			*this = m;
		 }
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~ProfileInfo() { }

	public:
		virtual void enter( short opt ) = 0;
		virtual void exit( short ) {
			this->mux.lockForWrite();
			--this->concurrentCount;
			this->mux.unLock();
		 }
		void setParentInfo( const IReflection* parent );


/** @name Getters
 * @{
 ******************************************************************************/
	public:
		inline const void* getPtr() const					{ return this->ptr; }
		std::string getPtrAsString() const;
		inline const std::string& getName() const			{ return this->name; }
		inline int64 getAccessCount() const					{ return this->accessCount; }
		inline int getConcurrentCount() const				{ return this->concurrentCount; }
		inline const void* getParentPtr() const				{ return this->parentPtr; }
		std::string getParentPtrAsString() const;

		inline const std::string& getParentClass() const	{ return this->parentClass; }
		inline const std::string& getParentName() const		{ return this->parentName; }

		static DataFieldCollector<ProfileInfo>* getDataFields();
//@}
/** @name Operators Overloading
 * @{
 ******************************************************************************/
	public:
		virtual ProfileInfo& operator=(const ProfileInfo& m);
		virtual bool operator==(const ProfileInfo &other) const;
		virtual bool operator!=(const ProfileInfo &other) const { return !(*this == other); }
//@}
/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const;
		virtual bool updateHash( DataHashContext* hash_context ) const;
//@}
	public:
		const void* ptr;			///<  pointer to object
		std::string name;			///< object name
		int64 accessCount;			///< global access counter
		int concurrentCount;		///< concurrent access counter
		const void* parentPtr;		///<  pointer to parent object
		std::string parentClass;	///< classname of parent object (owner)
		std::string parentName;		///< human friendly name of parent object (owner)
		MutexRW mux;				///< R/W access mutex of stats

}; // class def


class ProfileInfoMethod : public ProfileInfo
 {
	WOSH_SERIALIZABLE(wosh::ProfileInfoMethod)

	public:
		ProfileInfoMethod()
			: ProfileInfo(), methodClass("VOID"), linkedFunction(false), linkedParent(false) { }

	public:
		void enter( short opt );
		void setMethod( const Method* method, const MethodRunner* parent );

	public:
		inline const std::string& getMethodClass() const	{ return this->methodClass; }
		inline bool isLinkedFunction() const				{ return this->linkedFunction; }
		inline bool isLinkedParent() const					{ return this->linkedParent; }

		static DataFieldCollector<ProfileInfoMethod>* getDataFields();

	public:
		std::string methodClass;
		bool linkedFunction;
		bool linkedParent;

}; // class def


class ProfileInfoProperty : public ProfileInfo
 {
	WOSH_SERIALIZABLE(wosh::ProfileInfoProperty)

	public:
		ProfileInfoProperty()
			: ProfileInfo(), readCount(0), writeCount(0) { }

	public:
		void enter( short read_or_write );
		void setProperty( const Property* prop, const IPropertiesProviderListener* parent );

	public:
		inline int64 getReadCount() const		{ return this->readCount; }
		inline int64 getWriteCount() const		{ return this->writeCount; }

		static DataFieldCollector<ProfileInfoProperty>* getDataFields();

	public:
		int64 readCount;
		int64 writeCount;

}; // class def


class ProfileInfoConnector : public ProfileInfo
 {
	WOSH_SERIALIZABLE(wosh::ProfileInfoConnector)

	public:
		ProfileInfoConnector()
			: ProfileInfo(), inputCount(0), outputCount(0) { }

	public:
		void enter( short input_or_output );
		void setConnector( const BusConnector* prop, const IBusListener* parent );

	public:
		inline int64 getInputCount() const		{ return this->inputCount; }
		inline int64 getOutputCount() const		{ return this->outputCount; }

		static DataFieldCollector<ProfileInfoConnector>* getDataFields();

	public:
		int64 inputCount;
		int64 outputCount;

}; // class def


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef _ENABLE_PROFILING
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 #define PROFILING_INIT( OBJECT, PARENT )		wosh::SystemProfiler::getInstance().initializeProfileOf( OBJECT, PARENT );
 #define PROFILING_ENTER( OBJECT, ARGUMENT )	wosh::SystemProfiler::getInstance().enterProfileOf( OBJECT, ARGUMENT );
 #define PROFILING_EXIT( OBJECT, ARGUMENT )		wosh::SystemProfiler::getInstance().exitProfileOf( OBJECT, ARGUMENT );

// fptr : it is platform specific and only works on the x86 family of CPUs
 #ifdef _MSC_VER
 # define WOSH_DEPRECATE( OLD_FUNC_NAME, NEW_FUNC_NAME ) {	\
		void* fptr;											\
		__asm { mov fptr, ebp }								\
		wosh::SystemProfiler::getInstance().deprecated(OLD_FUNC_NAME, NEW_FUNC_NAME, fptr, __FILE__, __LINE__); }
 #else
 # define WOSH_DEPRECATE( OLD_FUNC_NAME, NEW_FUNC_NAME ) {	\
		wosh::SystemProfiler::getInstance().deprecated(OLD_FUNC_NAME, NEW_FUNC_NAME, 0, __FILE__, __LINE__); }
 #endif


class SystemProfiler
 {
	typedef MapT<const void*, ProfileInfoMethod*> tVoidPtrProfileInfoMethodMap;
	typedef MapT<const void*, ProfileInfoProperty*> tVoidPtrProfileInfoPropertyMap;
	typedef MapT<const void*, ProfileInfoConnector*> tVoidPtrProfileInfoConnectorMap;

	typedef ListT<DeprecatedFunctionInfo> tDeprecatedFunctionInfoList;

	//----------------------------------- used directly by SystemMonitor
	public:
		Table* getDeprecatedTable() const;
		Table* getProfilesMethodsTable( int64 access_threshold ) const;
		Table* getProfilesPropertiesTable( int64 access_threshold ) const;
		Table* getProfilesConnectorsTable( int64 access_threshold ) const;

	//----------------------------------- used directly by macros
	public:
		static SystemProfiler& getInstance();

	public:
		void deprecated( const char * OldFunctionName, const char * NewFunctionName,
						void* CalledFrom, const char * filename, unsigned int file_line );

	public:
		template<class OBJECT, class PARENT>
		void initializeProfileOf( const OBJECT* object, const PARENT* owner ) {
			getCreateProfile(object, owner);
		 }
		template<class OBJECT>
		void enterProfileOf( const OBJECT* object, short argument ) {
			ProfileInfo* info = static_cast<ProfileInfo*>( getCreateProfile(object, NULL) );
			if ( info == NULL ) return;
			info->enter(argument);
		 }
		template<class OBJECT>
		void exitProfileOf( const OBJECT* object, short argument ) {
			ProfileInfo* info = static_cast<ProfileInfo*>( getCreateProfile(object, NULL) );
			if ( info == NULL ) return;
			info->exit(argument);
		}

	protected:
		ProfileInfoProperty* getCreateProfile( const Property* object, const IPropertiesProviderListener* owner );
		ProfileInfoConnector* getCreateProfile( const BusConnector* object, const IBusListener* owner );
		ProfileInfoMethod* getCreateProfile( const Method* object, const MethodRunner* owner );

	public:
		virtual ~SystemProfiler();

	protected:
		SystemProfiler() { }

		tVoidPtrProfileInfoMethodMap profilesMethods;
		tVoidPtrProfileInfoPropertyMap profilesProperties;
		tVoidPtrProfileInfoConnectorMap profilesConnectors;

		tDeprecatedFunctionInfoList deprecatedList;

}; // class def

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
#else // _ENABLE_PROFILING
# undef PROFILING_INIT
# define PROFILING_INIT( OBJECT, PARENT )
# undef PROFILING_ENTER
# define PROFILING_ENTER( OBJECT, ARGUMENT )
# undef PROFILING_EXIT
# define PROFILING_EXIT( OBJECT, ARGUMENT )
# undef WOSH_DEPRECATE
# define WOSH_DEPRECATE( OLD_FUNC_NAME, NEW_FUNC_NAME )
#endif // _ENABLE_PROFILING
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


}; // namespace wosh

#endif //__WOSH_Core_SystemProfiler_H__
